Skip to content

[docs] Document terminal cleanup after crash or forced stop - #1503

Open
aspire-repo-bot[bot] wants to merge 1 commit into
release/13.5from
docs/pr-19344-31896366042-1-f14207b4b37e64b1
Open

[docs] Document terminal cleanup after crash or forced stop#1503
aspire-repo-bot[bot] wants to merge 1 commit into
release/13.5from
docs/pr-19344-31896366042-1-f14207b4b37e64b1

Conversation

@aspire-repo-bot

Copy link
Copy Markdown
Contributor

Documents changes from microsoft/aspire#19344

@IEvangelist

Targeting release/13.5 — the latest release branch on microsoft/aspire.dev — because release/13.6 (from the source PR milestone 13.6) does not exist there.

Why this PR is needed

microsoft/aspire#19344 makes WithTerminal() socket cleanup resilient across graceful stops (SIGTERM/Ctrl+C), forced termination, AppHost crashes, and reboots, adding a new public TerminalHostProcessRunner runner class and a background orphan-cleanup service. This is a user-visible reliability improvement (no more leaked sockets under ~/.aspire/trmnl/) for a feature (WithTerminal) that already has a dedicated docs page, but that page didn't previously mention cleanup/lifecycle behavior at all.

What changed

Added a new "Terminal cleanup after a crash or forced stop" section to app-host/with-terminal.mdx, explaining:

  • Automatic socket cleanup on normal stop, SIGTERM/Ctrl+C, and AppHost crash (parent-process watchdog)
  • Startup background sweep that reclaims sockets from confirmed-dead owners after reboot/unclean shutdown
  • That this behavior is automatic and run-mode only (not applicable to publish mode)

Files modified

  • src/frontend/src/content/docs/app-host/with-terminal.mdx — added a new section, no existing content changed.

No new pages were created; this is an addition to the existing WithTerminal page.

Generated by PR Documentation Check for #19344 · auto · 38.8 AIC · ⌖ 7.94 AIC · ⊞ 19.6K ·

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@aspire-repo-bot aspire-repo-bot Bot added the docs-from-code Copilot initiated issue from dotnet/aspire repo label Aug 15, 2026
@aspire-repo-bot

Copy link
Copy Markdown
Contributor Author

Frontend HTML artifact ready

The latest frontend build uploaded the frontend-dist artifact for PR #1503. Use the VS Code button below to open this PR with GitHub Artifacts Explorer and browse the built HTML locally.

VS Code: Open PR #1503 artifacts

This comment updates automatically when a new frontend build artifact is uploaded.

@IEvangelist
David Pine (IEvangelist) marked this pull request as ready for review August 15, 2026 17:38
Copilot AI lite review requested due to automatic review settings August 15, 2026 17:38

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds documentation to the existing WithTerminal AppHost page describing how terminal host Unix domain sockets are cleaned up after graceful stops, crashes/forced termination, and reboots/unclean shutdowns—reflecting the resilience improvements introduced in microsoft/aspire#19344.

Changes:

  • Added a new “Terminal cleanup after a crash or forced stop” section to explain automatic socket lifecycle behavior.
  • Documented both crash/forced-stop self-exit behavior and next-startup orphan socket sweeping.
  • Clarified that the cleanup behavior applies in run mode, not publish mode.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.


Each terminal host listens on a per-replica Unix domain socket under `~/.aspire/trmnl/` on Linux and macOS. Aspire cleans these sockets up automatically when a resource stops normally, but it's also resilient to less graceful endings:

- If the AppHost sends `SIGTERM` (for example, `docker stop` or a process manager shutting things down) or you interrupt it with `Ctrl+C`, the terminal host receives the signal, cancels its work, and unlinks its own socket before exiting.

@IEvangelist David Pine (IEvangelist) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated docs-accuracy review — Phases A + B

Phase A source of truth: microsoft/aspire release/13.5 @ 8ab6999850d96e0023670799edbd4bdc245ad63c (matches this PR's target branch release/13.5). Cross-checked against microsoft/aspire main @ 0cedb24b5a7e7f83887e7585e19ae47fbbe6af5d for context only.
Claims extracted: 6 → verified 2, verified-with-nuance 0, unverifiable 4, contradicted 0 (verdicts are against the target branch release/13.5).
Phase B: 1 route exercised (/app-host/with-terminal/) served from PR head b661eaa40 critical, 1 warning, 2 knowledge gaps.

⚠️ Key finding — version targeting

Every resilience behavior this section documents — signal-driven socket unlink, the parent-process watchdog, and the startup orphan sweep — was introduced by microsoft/aspire#19344 ("Handle SIGTERM in terminal host and GC orphaned sockets"), which is milestone 13.6, merged to main only. Its merge commit b777bb16 is not an ancestor of release/13.5, and none of the new symbols (TerminalHostProcessRunner, TerminalHostOrphanCleanupService, the terminal-host ParentProcessWatchdog wiring) exist on release/13.5.

So on the branch this PR targets (release/13.5), claims C3–C6 are unverifiable — the prose is factually accurate, but it describes 13.6 behavior on the 13.5 docs branch. Please confirm this section is intended to ship with 13.5, or retarget it to the 13.6 docs once that branch exists. Claims C1–C2 (socket location + cleanup on normal stop) are already true on release/13.5.


Phase A — Claim verification

The 4 unverifiable claims are posted as inline comments on their lines. The 2 verified claims are listed below.

Verified claims (2) — evidence on release/13.5
  • C1 — per-replica Unix domain socket under ~/.aspire/trmnl/ (line 172): verified. src/Shared/TerminalHost/TerminalHostPaths.cs defines TrmnlDirectoryName = "trmnl" and the socket path format {home}/.aspire/trmnl/{replicaId}.{sockPurpose}.sock; src/Aspire.Hosting/TerminalResourceBuilderExtensions.cs (L156–176) creates the files flat under ~/.aspire/trmnl/. Minor nuance: each replica actually has two sockets (control + consumer) plus a metadata.json sidecar, so "a per-replica Unix domain socket" (singular) is a small simplification. Not blocking.
  • C2 — automatic cleanup on normal stop (line 172): verified. src/Aspire.Hosting/TerminalResourceBuilderExtensions.cs (L270–293) registers IHostApplicationLifetime.ApplicationStoppedDeleteReplicaFiles(...), and the host children unlink their own UDS endpoints on graceful shutdown (comment at L273–275).

Phase B — Doc-tester results

Produced by the doc-tester skill (blind to source code), navigating the local dev server (http://localhost:4321/) serving PR head b661eaa4 via Playwright.

Documentation Test Report

Focus Area: New section "Terminal cleanup after a crash or forced stop" on /app-host/with-terminal/
Date: 2026-08-15
Tester: doc-tester agent
Server / ref: http://localhost:4321/ serving PR head b661eaa4 (branch pr-1503)
Routes exercised: /app-host/with-terminal/ → section #terminal-cleanup-after-a-crash-or-forced-stop

Summary

Category Passed Failed Warnings
Content Accuracy 1 0 1
Code Examples n/a (none in section) 0 0
CLI Commands n/a (none in section) 0 0
Links / Anchors 1 0 0

Critical Issues

None.

Warnings

Warning 1: "run mode" / "publish mode" used without explanation or link

Location: /app-host/with-terminal/#terminal-cleanup-after-a-crash-or-forced-stop, closing paragraph.
Issue: The final sentence distinguishes run mode and publish mode — Aspire-specific concepts — but neither is linked or explained on this page (each term appears exactly once, only in this new section, with no cross-reference; 64 links on the page, none pointing at a run/publish-mode concept). A first-time reader may not know what publish mode is or why terminal hosts wouldn't be materialized there.
Suggestion: Link "publish mode" / "run mode" to their concept page on first use.

Passed Checks

  • Section renders correctly: <h2> heading, table-of-contents entry, and self-anchor link (#terminal-cleanup-after-a-crash-or-forced-stop) are all present and functional.
  • Prose renders as one intro paragraph, a 3-item bullet list, and a closing paragraph; smart quotes and em-dashes render correctly; no raw markdown leaks into the page.
  • No console errors on page load (0 errors / 0 warnings).
  • Section is internally self-consistent and readable; the prerequisite terms "terminal host" and "replica" are introduced earlier on the same page (intro + "Terminals and replicas" section).

Knowledge Gaps

Knowledge Gap: SIGTERM / Unix domain socket

What I needed to know: what SIGTERM and a "Unix domain socket" are.
Source of my knowledge: Built-in/prior knowledge (NOT from documentation).
User impact: Developers from non-Unix / non-systems backgrounds may not recognize these. SIGTERM is softened by the "docker stop / process manager" example, which helps.
Recommendation: Reasonable to assume for this audience; optionally gloss "Unix domain socket."

Knowledge Gap: runtime behavior could not be reproduced

What I needed to do: Confirm sockets are actually removed after SIGTERM / crash / reboot.
Why blocked: WithTerminal is experimental and the doc states the sockets live on Linux and macOS; this test host is Windows, so ~/.aspire/trmnl/ socket cleanup cannot be exercised here. Per doc-tester rules I did not read source to fill this gap.
User impact: None to the reader — recorded as a tester limitation so the "blind user" runtime verification of this section is explicitly noted as incomplete.

Recommendations

  1. Priority fixes: None (no critical issues).
  2. Documentation gaps: Link run/publish mode on first use.
  3. Product issues: None discovered.

Verdict: COMMENT

No contradicted claims and no Phase B critical issues, so this is not REQUEST_CHANGES. It is not APPROVE because 4 claims are unverifiable on the target branch (the documented 13.6 feature is absent from release/13.5) and Phase B raised a warning + knowledge gaps. The prose itself is accurate against the code where the feature actually lives (main/13.6); the actionable item is the version-targeting question above.


Each terminal host listens on a per-replica Unix domain socket under `~/.aspire/trmnl/` on Linux and macOS. Aspire cleans these sockets up automatically when a resource stops normally, but it's also resilient to less graceful endings:

- If the AppHost sends `SIGTERM` (for example, `docker stop` or a process manager shutting things down) or you interrupt it with `Ctrl+C`, the terminal host receives the signal, cancels its work, and unlinks its own socket before exiting.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

C3 · unverifiable on the target branch (release/13.5).

If the AppHost sends SIGTERM … or you interrupt it with Ctrl+C, the terminal host receives the signal, cancels its work, and unlinks its own socket before exiting.

On microsoft/aspire release/13.5 (8ab6999) the terminal host has no SIGTERM/SIGINT handling — src/Aspire.TerminalHost/ contains no PosixSignal registration. This behavior was added by microsoft/aspire#19344 (milestone 13.6, base main): src/Aspire.TerminalHost/TerminalHostProcessRunner.cs (L45–89) registers SIGINT+SIGTERM and the first signal grants the host a bounded window to unlink its sockets. Accurate against main; absent on release/13.5.

Each terminal host listens on a per-replica Unix domain socket under `~/.aspire/trmnl/` on Linux and macOS. Aspire cleans these sockets up automatically when a resource stops normally, but it's also resilient to less graceful endings:

- If the AppHost sends `SIGTERM` (for example, `docker stop` or a process manager shutting things down) or you interrupt it with `Ctrl+C`, the terminal host receives the signal, cancels its work, and unlinks its own socket before exiting.
- If the AppHost process itself crashes or is killed without giving its children a chance to shut down, each terminal host detects that its parent process is gone and exits on its own shortly after.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

C4 · unverifiable on the target branch (release/13.5).

each terminal host detects that its parent process is gone and exits on its own shortly after.

No parent-process watchdog is wired into the terminal host on release/13.5. Added by microsoft/aspire#19344 (13.6): TerminalHostProcessRunner.cs (L23–27) starts ParentProcessWatchdog.Start(..., TerminalHostParentProcessId, ...), and src/Shared/ParentProcessWatchdog.cs (L9–63) cancels and force-exits (5 s grace, exit code 124) once the parent PID is no longer alive. Accurate against main; absent on release/13.5.


- If the AppHost sends `SIGTERM` (for example, `docker stop` or a process manager shutting things down) or you interrupt it with `Ctrl+C`, the terminal host receives the signal, cancels its work, and unlinks its own socket before exiting.
- If the AppHost process itself crashes or is killed without giving its children a chance to shut down, each terminal host detects that its parent process is gone and exits on its own shortly after.
- On the next AppHost startup, a background sweep reclaims any sockets left behind by replicas whose owning process is confirmed gone—for example, after a machine reboot or an unclean shutdown. Sockets belonging to a process that might still be running (or that Aspire can't confirm has exited) are left alone.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

C5 · unverifiable on the target branch (release/13.5).

a background sweep reclaims any sockets left behind by replicas whose owning process is confirmed gone … Sockets belonging to a process that might still be running (or that Aspire can't confirm has exited) are left alone.

There is no orphan-cleanup service on release/13.5. Added by microsoft/aspire#19344 (13.6): src/Aspire.Hosting/Lifecycle/TerminalHostOrphanCleanupService.cs — a BeforeStartEvent sweep (L61) that reclaims only confirmed-dead owners: ownerIsRunningcontinue (L365–367) and unableToInspectOwnercontinue with "leaving its artifacts in place" (L356–363), so only a confirmed-not-running owner reaches DeleteReplicaFiles (L374). The prose matches this implementation precisely. Accurate against main; absent on release/13.5.

- If the AppHost process itself crashes or is killed without giving its children a chance to shut down, each terminal host detects that its parent process is gone and exits on its own shortly after.
- On the next AppHost startup, a background sweep reclaims any sockets left behind by replicas whose owning process is confirmed gone—for example, after a machine reboot or an unclean shutdown. Sockets belonging to a process that might still be running (or that Aspire can't confirm has exited) are left alone.

You don't need to do anything to benefit from this—it runs automatically in run mode. It doesn't apply to publish mode, since publish never materializes terminal hosts or their sockets.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

C6 · unverifiable on the target branch (release/13.5).

it runs automatically in run mode. It doesn't apply to publish mode, since publish never materializes terminal hosts or their sockets.

The cleanup service this sentence describes does not exist on release/13.5. On main (via microsoft/aspire#19344, 13.6) the sweep subscribes only when executionContext.IsRunMode (TerminalHostOrphanCleanupService.cs L57), so the run-mode-only framing is correct there. Accurate against main; the described cleanup is absent on release/13.5.


## Terminal cleanup after a crash or forced stop

Each terminal host listens on a per-replica Unix domain socket under `~/.aspire/trmnl/` on Linux and macOS. Aspire cleans these sockets up automatically when a resource stops normally, but it's also resilient to less graceful endings:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is actually three sockets per replica (producer, consumer, and control), and the cleanup code removes all three. Could we use plural wording here? “a per-replica Unix domain socket” makes the cleanup model inaccurate.

@karolz-ms

Copy link
Copy Markdown

I am not sure what is the value of having this in the documentation. These socket files are just implementation details.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs-from-code Copilot initiated issue from dotnet/aspire repo

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants